#pragma once

#include <intrin.h>
#include "LogLevel.h"
#include "..\Common\StrTraits.h"

#ifdef GAOJIELOG_EXPORTS
#define GAOJIELOG_API __declspec(dllexport)
#else
#define GAOJIELOG_API __declspec(dllimport)
#endif

namespace Log
{

GAOJIELOG_API bool LogInit();
GAOJIELOG_API void LogExit();
GAOJIELOG_API bool LogWriteA(LPCVOID lpRetAddr, LogLevel logLevel, LPCSTR lpFormat, ...);
GAOJIELOG_API bool LogWriteW(LPCVOID lpRetAddr, LogLevel logLevel, LPCWSTR lpFormat, ...);

template<typename... Args>
inline bool _LogWrite(LPCVOID lpRetAddr, LogLevel logLevel, LPCSTR lpFormat, Args&&... args)
{
	return LogWriteA(lpRetAddr, logLevel, lpFormat, Str::TypeCheck<char>(std::forward<Args>(args))...);
}

template<typename... Args>
inline bool _LogWrite(LPCVOID lpRetAddr, LogLevel logLevel, LPCWSTR lpFormat, Args&&... args)
{
	return LogWriteW(lpRetAddr, logLevel, lpFormat, Str::TypeCheck<wchar_t>(std::forward<Args>(args))...);
}

template<typename... Args>
inline bool LogWrite(LPCVOID lpRetAddr, LogLevel logLevel, Args&&... args)
{
	if constexpr (sizeof...(Args) == 0)
		return LogWriteW(lpRetAddr, logLevel, nullptr);
	else
		return _LogWrite(lpRetAddr, logLevel, Str::TypeCast(std::forward<Args>(args))...);
}

template<typename... Args>
inline bool LogError(Args&&... args)
{
	return LogWrite(_ReturnAddress(), LogLevel::Error, std::forward<Args>(args)...);
}

template<typename... Args>
inline bool LogWarn(Args&&... args)
{
	return LogWrite(_ReturnAddress(), LogLevel::Warn, std::forward<Args>(args)...);
}

template<typename... Args>
inline bool LogInfo(Args&&... args)
{
	return LogWrite(_ReturnAddress(), LogLevel::Info, std::forward<Args>(args)...);
}

}	// namespace Log

using Log::LogInit;
using Log::LogExit;
using Log::LogError;
using Log::LogWarn;
using Log::LogInfo;
